#include "raid.h"
#include "logfile.h"

int estaSincronizado(int32_t sock)
{
	tipoDisco* ptrNuevoDiscos;
	pthread_mutex_lock( &mutexDiscos );
	ptrNuevoDiscos = listaDiscos;

	while(ptrNuevoDiscos != NULL && ptrNuevoDiscos->sockDisco != sock)
	{
		ptrNuevoDiscos = ptrNuevoDiscos->sgte;
	}
	if (ptrNuevoDiscos != NULL)
		pthread_mutex_unlock ( &mutexDiscos );
		return ptrNuevoDiscos->sinc;
	pthread_mutex_unlock ( &mutexDiscos );
	return 0;
}

int sincronizarCon( int32_t sockClon, int vecSectores[] , int32_t cantSectores ,char ID[16], int32_t sectoresSincro )
{
	int32_t z;
	Paquete* unPaquete = malloc (sizeof(Paquete));
	unPaquete->Datos = malloc (512);
	int32_t sockMaster;

	if( sectoresSincro < cantSectores )
	{
		for(z=0;z<16;z++)
			unPaquete->ID[z] = ID[z];
		unPaquete->Tipo = GET_SECTOR;
		unPaquete->Length = 512;
		for(z=0;z<512;z++)
			unPaquete->Datos[z] = EMPTY_MSG[z];

		pthread_mutex_lock( &mutexPedidos );
		for(z=0; (z<250 && sectoresSincro<cantSectores); z++,sectoresSincro++)   /* cantidad de pedidos que queres que meta de una */
		{
			pthread_mutex_lock( &mutexDiscos );
			sockMaster = proximoDisco();
			pthread_mutex_unlock ( &mutexDiscos );
			unPaquete->Sector = sectoresSincro;
			if(sockMaster != -1)
			{
				nuevoPedido(sockMaster,unPaquete);
				sem_post( &semPed );
			}
			else
			{
				raidFuncionando = 0;
				break;
			}
		}
		pthread_mutex_unlock ( &mutexPedidos );
	}
	free(unPaquete->Datos);
	free(unPaquete);
	if (sockMaster != -1)
		return sectoresSincro;
	else
		return -1;
}

void agregarSincro( char unID[16], int sockClon)
{
	tipoSincro* ptrNuevoSincro = (tipoSincro*) malloc ( sizeof(tipoSincro));
	int z;

	for(z=0;z<16;z++)
			ptrNuevoSincro->ID[z] = unID[z];
	ptrNuevoSincro->sectorListo = 1;
	ptrNuevoSincro->sock = sockClon;
	if(listaSincro != NULL)
	{
			ptrNuevoSincro->sgte = listaSincro;
			listaSincro = ptrNuevoSincro;
			return;
	}
	ptrNuevoSincro->sgte = NULL;
	listaSincro = ptrNuevoSincro;
	return;
}

int32_t proximoSectorAsinc( char unID[16] )
{
	tipoSincro* ptrNuevoSincro;
	int32_t sector = -1;

	ptrNuevoSincro = listaSincro;

	while( ptrNuevoSincro!= NULL && sonDistintos(unID,ptrNuevoSincro->ID) )
	{
		ptrNuevoSincro = ptrNuevoSincro->sgte;
	}
	if (ptrNuevoSincro != NULL)
		sector = ptrNuevoSincro->sectorListo+1;
	ptrNuevoSincro = NULL;
	free(ptrNuevoSincro);
	return sector;
}

int32_t sonDistintos(char unID[16],char otroID[16])
{
	int z;
		for(z=0;z<16;z++)
		{
			if( unID[z] != otroID[z] )
				return 1;
		}
	return 0;
}
void actualizarPedidosDe(sockPD)
{
	int32_t sockMaster;
	tipoPedido* ptrNuevoPedidos;
	int32_t i;
	Paquete* paquete = malloc (sizeof(Paquete));
	paquete->Datos = malloc (512);
	ptrNuevoPedidos = listaAtendidos;

	while( ptrNuevoPedidos != NULL )
	{
		if(ptrNuevoPedidos->sock == sockPD)
		{
			sockMaster = proximoDisco();
			if(sockMaster != -1)
				ptrNuevoPedidos->sock = sockMaster;
			else
			{
				raidFuncionando = 0;
				break;
			}
		listaAtendidos = ptrNuevoPedidos->sgte;
		for( i=0;i<16;i++)
			paquete->ID[i] = ptrNuevoPedidos->ID[i];
		paquete->Length = ptrNuevoPedidos->length;
		paquete->Tipo = ptrNuevoPedidos->tipo;
		paquete->Sector = ptrNuevoPedidos->sector;
		for( i=0;i<paquete->Length;i++)
			paquete->Datos[i] = ptrNuevoPedidos->msg[i];
		free( ptrNuevoPedidos->msg);
		free( ptrNuevoPedidos );
		ptrNuevoPedidos = listaAtendidos;
		pthread_mutex_lock( &mutexPedidos );
		nuevoPedido( sockMaster, paquete );
		sem_post( &semPed );
		pthread_mutex_unlock( &mutexPedidos );
		}
		else
			ptrNuevoPedidos = ptrNuevoPedidos->sgte;
	}
	return;
}
void eliminarAtendido( char IDmsg[16], int32_t sector )
{
	tipoPedido* ptrNuevoPedidos;
	tipoPedido* ptrAntPedidos;
	ptrNuevoPedidos = listaAtendidos;
	ptrAntPedidos = NULL;

	while( ptrNuevoPedidos != NULL && sonDistintos(IDmsg,ptrNuevoPedidos->ID) && ptrNuevoPedidos->sector != sector )
	{
		ptrAntPedidos = ptrNuevoPedidos;
		ptrNuevoPedidos = ptrNuevoPedidos->sgte;
	}

	if( ptrNuevoPedidos != NULL )
	{
		if( ptrAntPedidos != NULL )
		{
			if(ptrNuevoPedidos->sgte != NULL)
				ptrAntPedidos->sgte = ptrNuevoPedidos->sgte;
			else
				ptrAntPedidos->sgte = NULL;
		}
		else
			listaAtendidos = ptrNuevoPedidos->sgte;
	}
	free(ptrNuevoPedidos->msg);
	free(ptrNuevoPedidos);
	return;
}
void eliminarPedido( char IDmsg[16], int32_t sector )
{
	tipoPedido* ptrNuevoPedidos;
	tipoPedido* ptrAntPedidos;
	ptrNuevoPedidos = listaPedidos;
	ptrAntPedidos = NULL;

	while( ptrNuevoPedidos != NULL && !sonDistintos(IDmsg,ptrNuevoPedidos->ID) && ptrNuevoPedidos->sector != sector )
	{
		ptrAntPedidos = ptrNuevoPedidos;
		ptrNuevoPedidos = ptrNuevoPedidos->sgte;
	}

	if( ptrNuevoPedidos != NULL )
	{
		if( ptrAntPedidos != NULL )
		{
			if(ptrNuevoPedidos->sgte != NULL)
				ptrAntPedidos->sgte = ptrNuevoPedidos->sgte;
			else
				ptrAntPedidos->sgte = NULL;
		}
		else
			listaPedidos = ptrNuevoPedidos->sgte;
	}
	free(ptrNuevoPedidos->sgte);
	free(ptrNuevoPedidos);
	return;
}
void eliminarSincro( char unID[] )
{
	tipoSincro* ptrSincroActual;
	tipoSincro* ptrSincroAnterior;
	ptrSincroActual = listaSincro;
	ptrSincroAnterior = NULL;

	while( ptrSincroActual != NULL && sonDistintos(unID,ptrSincroActual->ID)  )
	{
		ptrSincroAnterior = ptrSincroActual;
		ptrSincroActual = ptrSincroActual->sgte;
	}
	if( ptrSincroActual != NULL )
	{
		ptrSincroActual->sectorListo = -1;
	/*  if( ptrSincroAnterior != NULL )
		{
			if(ptrSincroActual->sgte != NULL)
				ptrSincroAnterior->sgte = ptrSincroActual->sgte;
			else
				ptrSincroAnterior->sgte = NULL;
		}
		else
			listaSincro = ptrSincroActual->sgte;
*/
	}
	return;
}
void eliminarDisco( int32_t sockPD )
{
	tipoDisco* ptrDiscoActual;
	tipoDisco* ptrDiscoAnterior;
	ptrDiscoActual = listaDiscos;
	ptrDiscoAnterior = NULL;

	while( ptrDiscoActual != NULL && ptrDiscoActual->sockDisco != sockPD )
	{
		ptrDiscoAnterior = ptrDiscoActual;
		ptrDiscoActual = ptrDiscoActual->sgte;
	}
	if( ptrDiscoActual != NULL )
	{
		if( ptrDiscoAnterior != NULL )
		{
			if(ptrDiscoActual->sgte != NULL)
				ptrDiscoAnterior->sgte = ptrDiscoActual->sgte;
			else
				ptrDiscoAnterior->sgte = NULL;
		}
		else
			listaDiscos = ptrDiscoActual->sgte;

	}
	free(ptrDiscoActual);
	return;
}
int unDiscoSinc()
{
	tipoDisco* ptrNuevoDiscos;
	int disco = 0;

	ptrNuevoDiscos = listaDiscos;
	while( ptrNuevoDiscos != NULL && ptrNuevoDiscos->sinc != 1 )
	{
		ptrNuevoDiscos = ptrNuevoDiscos->sgte;
	}
	if (ptrNuevoDiscos != NULL)
	{
		disco = ptrNuevoDiscos->sockDisco;
	}
	return disco;
}
char* nombreDisco(int sockPD)
{
	tipoDisco* ptrNuevoDiscos;
	char* nombre = malloc (17);

	ptrNuevoDiscos = listaDiscos;

	while(ptrNuevoDiscos != NULL && ptrNuevoDiscos->sockDisco != sockPD)
	{
		ptrNuevoDiscos = ptrNuevoDiscos->sgte;
	}
	strcpy(nombre,ptrNuevoDiscos->nombre);
	ptrNuevoDiscos = NULL;
	free(ptrNuevoDiscos);
	return nombre;
}

int esDisco( int buscaSocket)
{
	tipoDisco* ptrNuevoDiscos;

	ptrNuevoDiscos = listaDiscos;

	while( (ptrNuevoDiscos != NULL) && (ptrNuevoDiscos->sockDisco != buscaSocket )   )
	{
		ptrNuevoDiscos = ptrNuevoDiscos->sgte;
	}
	if(ptrNuevoDiscos != NULL)
	{
		buscaSocket = ptrNuevoDiscos->sockDisco;
	}
	ptrNuevoDiscos = NULL;
	free(ptrNuevoDiscos);
	return buscaSocket;
}

char* buscacfg (char* cad) {

	FILE* archivo;
	char* loc = (char*) malloc (128);
	char* buffer = (char*) malloc (128);   /* reserva de memoria */

	archivo = fopen("config.ini","r");   /* abre el archivo */
	if(archivo == NULL)
	printf("el archivo no se encuentra\n");	/* error de apertura */
	while(feof(archivo) == 0 )
	{		/* mientras se pueda leer el archivo */
		fscanf(archivo,"%s",buffer);	/* se lee */
		loc = strstr(buffer,cad);	/* se localiza en el stream la palabra clave */
		if(loc != NULL)
		{		/* si se localizo loc != NULL */
			cad = strstr(buffer,"]=");	/* se localiza el final de la estructura */
			loc = NULL;			/* cambio el puntero a NULL para no perder la info para el return */
			buffer = NULL;
			free(buffer);
			free(loc);			/* se libera la memoria */
			fclose(archivo);		/* se cierra el archivo */
			return cad+2;			/* se suma 2 al puntero por la perdida de la estructura */
		}
	}
	if (loc == NULL)
	{			/* si no se encontro la palabra clave */
		free(buffer);
		free(loc);
		fclose(archivo);
		/* se libera la memoria, se cierra el archivo y devuelve "CFG No encontrada" */
		}
	return "0";
}			/* al utilizar esta funcion es necesario que el parametro que utiliza
			sea los mas parecido posible al string que aparece en el archivo de configuracion
			por ejemplo si llega al parametro KSS, y en el archivo esta [KSS1]:123123 y [KSS2]:090898
			retornara el primer valor que encuentre. */

int32_t initSockGral(void)
{
    int32_t sockfd=1;
    int32_t optval;

    optval = 1;
	if ((sockfd = socket(AF_INET, SOCK_STREAM, 0)) == -1)
	{
        printf("No se pudo crear el socket General, initSockGral() en socket.c\n");
		return -1;
	}

	struct sockaddr_in my_addr;				/*	informaci�n sobre mi direcci�n	*/
	my_addr.sin_family = AF_INET; 			/*	Ordenaci�n de bytes de la m�quina	*/
	my_addr.sin_port = htons(atoi(buscacfg("SOCKGRAL-PORT"))); 		/*	short, Ordenaci�n de bytes de la red	*/
	my_addr.sin_addr.s_addr = INADDR_ANY; 	/*	Rellenar con mi direcci�n IP */

	memset(&(my_addr.sin_zero), '\0', 8);	/*	Poner a cero el resto de la estructura	*/
	setsockopt(sockfd, SOL_SOCKET, SO_REUSEADDR, &optval, sizeof optval);
	if (bind(sockfd, (struct sockaddr *)&my_addr, sizeof(struct sockaddr))== -1)
		{
		printf("Error en el bind(), initSockFSS() en socket.c\n");
		return -1;
		}

    if ( listen(sockfd, BACKLOG) < 0 )
       {
	   printf("Error en el listen(), initSock() en socket.c\n");
       return -1;
       }
    return sockfd;
}

void agregarDisco ( int32_t sock, Paquete* paquete )
{
    tipoDisco* ptrNuevo = (tipoDisco*) malloc (sizeof(tipoDisco));
    ptrNuevo->nombre = malloc(paquete->Length);
    int z;

    for(z=0;z<paquete->Length;z++)
    	ptrNuevo->nombre[z] = paquete->Datos[z];
    ptrNuevo->flag = 0;
    ptrNuevo->sinc = 0;
    ptrNuevo->sockDisco = sock;
    if (listaDiscos != NULL)
        ptrNuevo->sgte = listaDiscos;
    else
    {
        ptrNuevo->sgte = NULL;
        ptrNuevo->sinc = 1;
    }
    listaDiscos = ptrNuevo;
    return;
}

void RandomGG(char dst[16], int size)
{
   static const char text[] = "abcdefghijklmnopqrstuvwxyz"
           "0123456789"
                              "ABCDEFGHIJKLMNOPQRSTUVWXYZ";
   int i, len = (size);
   for ( i = 0; i < len; ++i )
   {
      dst[i] = text[rand() % (sizeof text - 1)];
   }
}

///Serializa el contenido de una struc Paquete. Transforma todo en un char* de memoria contigua.
/// La funcion retorna un char* que debera ser enviado por el send correspondiente.
char* Serializar(Paquete* unPaquete)
{
	char* retorno = (char*)malloc( 16 + 1 + 2 + 4 + (unPaquete->Length));
	memcpy(retorno,&unPaquete->ID,16);
	memcpy(retorno+16,&unPaquete->Sector,4);
	memcpy(retorno+16+4,&unPaquete->Tipo,1);
	memcpy(retorno+1+16+4,&unPaquete->Length,2);
	memcpy(retorno+1+16+2+4,unPaquete->Datos,unPaquete->Length);
	return retorno;
}

/// DesSerializa un char* resultante de una serializacion, a una struct Paquete.
/// Recibe un stream (el q va a venir del RECV) y lo transforma en un "Paquete"
Paquete* DesSerializar(char *unStream)
{
	Paquete* unPaquete = malloc(sizeof(Paquete));
	memcpy(&unPaquete->ID,unStream,16);
	memcpy(&unPaquete->Sector,unStream+16,4);
	memcpy(&unPaquete->Tipo,unStream+16+4,1);
	memcpy(&unPaquete->Length,unStream+1+16+4,2);
	unPaquete->Datos=malloc(unPaquete->Length);
	memcpy(unPaquete->Datos,unStream+16+1+2+4,unPaquete->Length);
	return unPaquete;
}

int32_t responderHandshake ( int32_t sock )
{
    char*  bufferSalida;
    Paquete* unPaquete = malloc (sizeof(Paquete));

    RandomGG(unPaquete->ID,16);
    unPaquete->Tipo = HANDSHAKE_OK;
    unPaquete->Length = 0;
    unPaquete->Datos = malloc (1);
    unPaquete->Datos = '\0';
    bufferSalida = Serializar(unPaquete);
    if ( send(sock, bufferSalida, 16+1+4+2+1, 0) < 0)
    {
        perror("send() UNIX failed\n");
        return -1;
    }
    free( bufferSalida );
    free(unPaquete->Datos);
    free(unPaquete);
    return 1;
}

void reverse(char s[])
{
    int i, j;
    char c;

    for (i = 0, j = strlen(s)-1; i<j; i++, j--)
    {
        c = s[i];
        s[i] = s[j];
        s[j] = c;
    }
}

void itoa(int n, char s[])
{
    int i, sign;
    if ((sign = n) < 0)  /* record sign */
        n = -n;          /* make n positive */
    i = 0;
    do {       /* generate digits in reverse order */
        s[i++] = n % 10 + '0';   /* get next digit */
    } while ((n /= 10) > 0);     /* delete it */
    if (sign < 0)
        s[i++] = '-';
    s[i] = '\0';
    reverse(s);
}

int buscaDisco ( int sockDisco )
{
    tipoDisco* ptrNuevo;
    int sock;
    ptrNuevo = listaDiscos;
    while ( sockDisco != ptrNuevo->sockDisco )
          ptrNuevo = ptrNuevo->sgte;
    if ( ptrNuevo == NULL )
        {
        return -1;
        }
    sock = ptrNuevo->sockDisco;
    return sock;
}

int proximoDisco(void)
{
	tipoDisco* ptrNuevo;
	tipoDisco* ptrSincro;
    int32_t sock,sockSincro;
    sockSincro = 0;
    ptrNuevo = listaDiscos;
    while ( ptrNuevo != NULL )
    {
    	if( ptrNuevo->sinc == 1 && sockSincro == 0 )
    	{
    		sockSincro = ptrNuevo->sockDisco;
    		ptrSincro = ptrNuevo;
    	}
    	if ( ptrNuevo->sinc == 1 && ptrNuevo->flag == 1)
    	{
    		sock = ptrNuevo->sockDisco;
    		ptrNuevo->flag = 0;
    		if(ptrNuevo->sgte != NULL) /* marcar al siguiente que va a ser leido */
    		{
    			ptrNuevo = proximoDiscoParaLeer(ptrNuevo->sgte);
    			if ( ptrNuevo != NULL )
    				ptrNuevo->flag = 1;
    			else
    				ptrSincro->flag = 1;
    		}
    		return sock;

    	}
    	ptrNuevo = ptrNuevo->sgte;
    }
    if ( sockSincro != 0 )
    {
    	ptrSincro->flag = 0;
    	ptrNuevo = proximoDiscoParaLeer(ptrSincro->sgte);
    	if ( ptrNuevo != NULL )
    		ptrNuevo->flag = 1;
    	else
    		ptrSincro->flag = 1;
    	return sockSincro;
    }
    else
    	return -1;
}
tipoDisco* proximoDiscoParaLeer(tipoDisco* ptr)
{
	while ( ptr != NULL && ptr->sinc != 1)
		ptr = ptr->sgte;

		if( ptr != NULL )
			return ptr;
		else
			return NULL;

}
int sinDiscosSinc(void)
{
	tipoDisco* ptrDisco;
	ptrDisco = listaDiscos;
	while( ptrDisco != NULL && ptrDisco->sinc != 1 )
		ptrDisco = ptrDisco->sgte;
	if ( ptrDisco != NULL )
		return 0;
	else
		return 1;
}

int nuevoAtendido(int sock, Paquete* paquete)
{
	tipoPedido* ptrNuevo = (tipoPedido*) malloc ( sizeof(tipoPedido));
	ptrNuevo->msg = (unsigned char*) malloc (512);
	tipoPedido* ptrActual;
	int z;
	for(z=0;z<16;z++)
		ptrNuevo->ID[z] = paquete->ID[z];
	if(paquete->Tipo == GET_SECTOR)
	{
		for(z=0;z<paquete->Length;z++)
			ptrNuevo->msg[z] = EMPTY_MSG[z];
		ptrNuevo->length = 512;
	}
	if(paquete->Tipo == PUT_SECTOR || paquete->Tipo == PUT_SECTOR_SINC )
	{
		for(z=0;z<paquete->Length;z++)
			ptrNuevo->msg[z] = paquete->Datos[z];
		ptrNuevo->length = 512;
	}
	ptrNuevo->sock = sock;
	ptrNuevo->sector = paquete->Sector;
	ptrNuevo->tipo = paquete->Tipo;
	ptrNuevo->atendido = 0;
	ptrNuevo->sgte = NULL;

	ptrActual = listaAtendidos;
	if( ptrActual != NULL)
	{
		while(ptrActual->sgte != NULL)
			ptrActual = ptrActual->sgte;
		ptrActual->sgte = ptrNuevo;
	}
	else
	{
		ptrActual = ptrNuevo;
		listaAtendidos = ptrActual;
	}
	return 1;
}
int nuevoPedidoAdelante( int sock, Paquete* paquete)
{
	tipoPedido* ptrNuevo = (tipoPedido*) malloc ( sizeof(tipoPedido));
	ptrNuevo->msg = (unsigned char*) malloc (512);
	int z;

	for(z=0;z<16;z++)
		ptrNuevo->ID[z] = paquete->ID[z];
	if(paquete->Tipo == GET_SECTOR)
	{
		for(z=0;z<paquete->Length;z++)
			ptrNuevo->msg[z] = EMPTY_MSG[z];
		ptrNuevo->length = 512;
	}
	if(paquete->Tipo == PUT_SECTOR || paquete->Tipo == PUT_SECTOR_SINC )
	{
		for(z=0;z<paquete->Length;z++)
			ptrNuevo->msg[z] = paquete->Datos[z];
		ptrNuevo->length = 512;
	}
	ptrNuevo->sock = sock;
	ptrNuevo->sector = paquete->Sector;
	ptrNuevo->tipo = paquete->Tipo;
	ptrNuevo->atendido = 0;
	ptrNuevo->sgte = listaPedidos;
	listaPedidos = ptrNuevo;
	return 1;
}
int nuevoPedidoSincro(int sock, Paquete* paquete)
{
	tipoPedido* ptrNuevo = (tipoPedido*) malloc ( sizeof(tipoPedido));
	ptrNuevo->msg = (unsigned char*) malloc (512);
	tipoPedido* ptrActual;
	int z;
	for(z=0;z<16;z++)
		ptrNuevo->ID[z] = paquete->ID[z];
	if(paquete->Tipo == GET_SECTOR)
	{
		for(z=0;z<paquete->Length;z++)
			ptrNuevo->msg[z] = EMPTY_MSG[z];
		ptrNuevo->length = 512;
	}
	if(paquete->Tipo == PUT_SECTOR || paquete->Tipo == PUT_SECTOR_SINC )
	{
		for(z=0;z<paquete->Length;z++)
			ptrNuevo->msg[z] = paquete->Datos[z];
		ptrNuevo->length = 512;
	}
	ptrNuevo->sock = sock;
	ptrNuevo->sector = paquete->Sector;
	ptrNuevo->tipo = paquete->Tipo;
	ptrNuevo->atendido = 0;
	ptrNuevo->sgte = NULL;

	ptrActual = listaPedidosSincro;
	if( ptrActual != NULL)
	{
		listaPedidosSincroLast->sgte = ptrNuevo;
		listaPedidosSincroLast = ptrNuevo;
	}
	else
	{
		listaPedidosSincro = ptrNuevo;
		listaPedidosSincroLast = ptrNuevo;
	}
	return 1;
}

int nuevoPedido(int sock, Paquete* paquete)
{
	tipoPedido* ptrNuevo = (tipoPedido*) malloc ( sizeof(tipoPedido));
	ptrNuevo->msg = (unsigned char*) malloc (512);
	tipoPedido* ptrActual;
	int z;
	for(z=0;z<16;z++)
		ptrNuevo->ID[z] = paquete->ID[z];
	if(paquete->Tipo == GET_SECTOR)
	{
		for(z=0;z<paquete->Length;z++)
			ptrNuevo->msg[z] = EMPTY_MSG[z];
		ptrNuevo->length = 512;
	}
	if(paquete->Tipo == PUT_SECTOR || paquete->Tipo == PUT_SECTOR_SINC )
	{
		for(z=0;z<paquete->Length;z++)
			ptrNuevo->msg[z] = paquete->Datos[z];
		ptrNuevo->length = 512;
	}
	ptrNuevo->sock = sock;
	ptrNuevo->sector = paquete->Sector;
	ptrNuevo->tipo = paquete->Tipo;
	ptrNuevo->atendido = 0;
	ptrNuevo->sgte = NULL;

	ptrActual = listaPedidos;
	if( ptrActual != NULL)
	{
		listaPedidosLast->sgte = ptrNuevo;
		listaPedidosLast = ptrNuevo;
	}
	else
	{
		listaPedidos = ptrNuevo;
		listaPedidosLast = ptrNuevo;
	}
	return 1;
}

void discoSincronizadoOK(int32_t sockPD)
{
	tipoDisco* ptrNuevoDiscos;

	ptrNuevoDiscos = listaDiscos;

	while ( ptrNuevoDiscos != NULL && ptrNuevoDiscos->sockDisco != sockPD)
		ptrNuevoDiscos = ptrNuevoDiscos->sgte;
	if (ptrNuevoDiscos != NULL)
		ptrNuevoDiscos->sinc = 1;
	printf("Disco %s sincronizado correctamente\n", nombreDisco(sockPD));
	return;
}

int32_t esPedidoSincro(char unID[16])
{
	tipoSincro* ptrNuevoSincro;
	int32_t devolver = 0;

	ptrNuevoSincro = listaSincro;

	while(ptrNuevoSincro != NULL && sonDistintos(unID,ptrNuevoSincro->ID))
		ptrNuevoSincro = ptrNuevoSincro->sgte;
	if(ptrNuevoSincro != NULL)
	{
		if( ptrNuevoSincro->sectorListo != -1)
			devolver = ptrNuevoSincro->sock;
		else
			devolver = ptrNuevoSincro->sectorListo;
	}
	return devolver;
}

int32_t verificarPedidosSincro(int32_t vecSincro[],int32_t sectores)
{
	int32_t i;
	for(i=0;i<sectores;i++)
	{
		if( vecSincro[i] != 1 )
			return 0;
	}
	return 1;
}
void replicarPedido(Paquete* unPaquete)
{
	int32_t sock;
	tipoDisco* ptrNuevoDisco = listaDiscos;
	pthread_mutex_lock( &mutexDiscos );
	while( ptrNuevoDisco != NULL )
	{
		sock = ptrNuevoDisco->sockDisco;
		nuevoPedido(sock,unPaquete);
		sem_post( &semPed );
		ptrNuevoDisco = ptrNuevoDisco->sgte;
	}
	pthread_mutex_unlock( &mutexDiscos );
}
void agregarPUTwait(int32_t sock, Paquete* paquete)
{
	tipoPedido* ptrNuevo = malloc ( sizeof(tipoPedido) );
	tipoPedido* ptrActual;
	int z;
	for(z=0;z<16;z++)
		ptrNuevo->ID[z] = paquete->ID[z];
	if(paquete->Tipo == GET_SECTOR)
	{
		for( z=0;z<ptrNuevo->length;z++)
			ptrNuevo->msg[z] = paquete->Datos[z];
		ptrNuevo->length = paquete->Length;
	}
	if(paquete->Tipo == PUT_SECTOR)
	{
		for(z=0;z<512;z++)
			ptrNuevo->msg[z] = paquete->Datos[z];
		ptrNuevo->length = paquete->Length;
	}
	ptrNuevo->sock = sock;
	ptrNuevo->sector = paquete->Sector;
	ptrNuevo->tipo = paquete->Tipo;
	ptrNuevo->atendido = 0;
	ptrNuevo->sgte = NULL;

	ptrActual = listaPUTwait;
	if( ptrActual != NULL)
	{
			while(ptrActual->sgte != NULL)
				ptrActual = ptrActual->sgte;
			ptrActual->sgte = ptrNuevo;
	}
	else
	{
		ptrActual = ptrNuevo;
		listaPUTwait = ptrActual;
	}
	return;
}

Paquete* revisarPUTwait(int32_t sockPD,int vecSincro[], Paquete* paquete)
{
	tipoPedido* ptrNuevoPedidos;
	tipoPedido* ptrAntPedidos;
	int32_t i;

	ptrNuevoPedidos = listaPUTwait;
	ptrAntPedidos = NULL;
	while( ptrNuevoPedidos != NULL && ptrNuevoPedidos->sock != sockPD )
	{
		ptrAntPedidos = ptrNuevoPedidos;
		ptrNuevoPedidos = ptrNuevoPedidos->sgte;
	}
	if( ptrNuevoPedidos != NULL && vecSincro[ptrNuevoPedidos->sector] == 1 )
	{

		if( ptrAntPedidos != NULL )
		{
			if(ptrNuevoPedidos->sgte != NULL)
				ptrAntPedidos->sgte = ptrNuevoPedidos->sgte;
			else
				ptrAntPedidos->sgte = NULL;
		}
		else
			listaPUTwait = ptrNuevoPedidos->sgte;
		paquete->Length = ptrNuevoPedidos->length;
		paquete->Sector = ptrNuevoPedidos->sector;
		paquete->Tipo = ptrNuevoPedidos->tipo;
		for(i=0;i<16;i++)
			paquete->ID[i] = ptrNuevoPedidos->ID[i];
		for(i=0;i<paquete->Length;i++)
			paquete->Datos[i] = ptrNuevoPedidos->msg[i];
		free(ptrNuevoPedidos);
		return paquete;
	}
	paquete->Tipo = 'X';
	return paquete;

}

int otroDiscoConMismoNombre( unsigned char* nombre1)
{
	tipoDisco* ptrNuevoDisco;
	ptrNuevoDisco = listaDiscos;
	while(ptrNuevoDisco != NULL && strcmp( (char*) nombre1, ptrNuevoDisco->nombre) != 0 )
	{
		ptrNuevoDisco = ptrNuevoDisco->sgte;
	}
	if ( ptrNuevoDisco != NULL )
	{
		return 1;
	}
	return 0;
}
int atenderPedidoSincro ( tipoPedido* ptrNuevoPedidos, int32_t sockPD, int vecSincro[] )
{
	Paquete* paquete = malloc (sizeof(Paquete));
	paquete->Datos = malloc (512);
	int32_t i,rc;
	char* bufferSalida;

	for(i=0;i<16;i++)
		paquete->ID[i] = ptrNuevoPedidos->ID[i];
	if( ptrNuevoPedidos != NULL && ptrNuevoPedidos->tipo == PUT_SECTOR_SINC )
	{
		paquete->Length = 512;
		paquete->Tipo = PUT_SECTOR;
		paquete->Sector = ptrNuevoPedidos->sector;
		for(i=0;i<512;i++)
			paquete->Datos[i] = ptrNuevoPedidos->msg[i];
		bufferSalida = Serializar(paquete);
//		printf("Escribe sector: %d\n",paquete->Sector);
		rc = send( sockPD, bufferSalida ,535, 0 );
		if ( rc < 0 )
		{
			free( bufferSalida );
			free( paquete->Datos);
			free( paquete );
			return -1;
		}
		else
		{
			free( bufferSalida );
			vecSincro[paquete->Sector]=1;
		}
	}
	free( paquete->Datos);
	free( paquete );
	return 1;
}

int atenderPedido ( tipoPedido* ptrNuevoPedidos, int32_t sockPD, int vecSincro[] )
{
	Paquete* paquete = malloc (sizeof(Paquete));
	paquete->Datos = malloc (512);
	int32_t i,rc;
	char* bufferSalida;

	for(i=0;i<16;i++)
		paquete->ID[i] = ptrNuevoPedidos->ID[i];
	if( ptrNuevoPedidos != NULL && ptrNuevoPedidos->tipo == GET_SECTOR )
	{
		paquete->Length = 512;
		paquete->Sector = ptrNuevoPedidos->sector;
		paquete->Tipo = ptrNuevoPedidos->tipo;
		for(i=0;i<512;i++)
			paquete->Datos[i] = ptrNuevoPedidos->msg[i];
		bufferSalida = Serializar(paquete);
		rc = send( sockPD, bufferSalida ,535, 0 );
		if ( rc < 0)
		{
			free( bufferSalida );
			free( paquete->Datos);
			free( paquete );
			return -1;
		}
		else
		{
			free( bufferSalida );
			pthread_mutex_lock( &mutexAtendidos );
			nuevoAtendido( sockPD, paquete );
			pthread_mutex_unlock( &mutexAtendidos );
		}
	}
	if( ptrNuevoPedidos != NULL && ptrNuevoPedidos->tipo == PUT_SECTOR_SINC )
	{
		paquete->Length = 512;
		paquete->Tipo = PUT_SECTOR;
		paquete->Sector = ptrNuevoPedidos->sector;
		for(i=0;i<512;i++)
			paquete->Datos[i] = ptrNuevoPedidos->msg[i];
		bufferSalida = Serializar(paquete);
		rc = send( sockPD, bufferSalida ,535, 0 );
		if ( rc < 0 )
		{
			free( bufferSalida );
			free( paquete->Datos);
			free( paquete );
			return -1;
		}
		else
		{
			free( bufferSalida );
			vecSincro[paquete->Sector]=1;
		}
	}
	if( ptrNuevoPedidos != NULL && ptrNuevoPedidos->tipo == PUT_SECTOR )
	{
		paquete->Length = 512;
		paquete->Tipo = PUT_SECTOR;
		paquete->Sector = ptrNuevoPedidos->sector;
		for(i=0;i<512;i++)
			paquete->Datos[i] = ptrNuevoPedidos->msg[i];
		if( estaSincronizado(sockPD) )
		{
			bufferSalida = Serializar(paquete);
			rc = send(sockPD, bufferSalida ,535,0);
			if ( rc < 0)
			{
				free( bufferSalida );
				free( paquete->Datos);
				free( paquete );
				return -1;
			}
			else
			{
				free( bufferSalida );
				vecSincro[paquete->Sector]=1;
			}
		}
		else
		{
			if ( vecSincro[paquete->Sector] == 1 )
			{
				bufferSalida = Serializar(paquete);
				rc = send(sockPD, bufferSalida ,16+4+2+1+512,0);
				if ( rc < 0)
				{
					free( bufferSalida );
					free( paquete->Datos);
					free( paquete );
					return -1;
				}
				else
				{
					free( bufferSalida );
					vecSincro[paquete->Sector]=1;
				}
			}
			else
			{
				agregarPUTwait(sockPD,paquete);
			}
		}
	}
	free( paquete->Datos);
	free( paquete );
	return 1;
}

void actualizarPedidosAtendidos( sockPD )
{
	tipoPedido* ptrNuevoPedidos;
	tipoPedido* ptrAntPedidos;
	int32_t i;
	int32_t sockMaster;
	Paquete* paquete = malloc (sizeof(Paquete));
	paquete->Datos = malloc (512);

	ptrNuevoPedidos = listaAtendidos;
	ptrAntPedidos = NULL;

	while ( ptrNuevoPedidos != NULL )
	{
		ptrAntPedidos = NULL;
		while( ptrNuevoPedidos != NULL && ptrNuevoPedidos->sock != sockPD )
		{
			ptrAntPedidos = ptrNuevoPedidos;
			ptrNuevoPedidos = ptrNuevoPedidos->sgte;
		}
		if( ptrNuevoPedidos != NULL )
		{
			if( ptrAntPedidos != NULL )
			{
				if(ptrNuevoPedidos->sgte != NULL)
					ptrAntPedidos->sgte = ptrNuevoPedidos->sgte;
				else
				{
					ptrAntPedidos->sgte = NULL;
				}
			}
			else
				listaAtendidos = ptrNuevoPedidos->sgte;
			paquete->Length = ptrNuevoPedidos->length;
			paquete->Sector = ptrNuevoPedidos->sector;
			paquete->Tipo = ptrNuevoPedidos->tipo;
			for(i=0;i<16;i++)
				paquete->ID[i] = ptrNuevoPedidos->ID[i];
			for(i=0;i<paquete->Length;i++)
				paquete->Datos[i] = ptrNuevoPedidos->msg[i];
			sockMaster = proximoDisco();
			if( sockMaster != -1)
			{
				pthread_mutex_lock( &mutexPedidos );
				nuevoPedido( sockMaster, paquete);
				sem_post( &semPed );
				pthread_mutex_unlock( &mutexPedidos );
			}
			else
			{
				raidFuncionando = 0;
				break;
			}
			free( ptrNuevoPedidos->msg );
			free( ptrNuevoPedidos );
			free( paquete->Datos );
			free( paquete );
		}
	}
	return;
}

void eliminarPedidosSincroDe( int32_t sockPD )
{
	tipoPedido* ptrNuevoPedidos;
	tipoPedido* ptrAntPedidos;
	ptrNuevoPedidos = listaPedidosSincro;
	ptrAntPedidos = NULL;

	while ( ptrNuevoPedidos != NULL )
	{
		ptrNuevoPedidos = listaPedidosSincro;
		while( ptrNuevoPedidos != NULL && ptrNuevoPedidos->sock != sockPD )
		{
			ptrAntPedidos = ptrNuevoPedidos;
			ptrNuevoPedidos = ptrNuevoPedidos->sgte;
		}
		if( ptrNuevoPedidos != NULL )
		{
			if( ptrAntPedidos != NULL )
			{
				if(ptrNuevoPedidos->sgte != NULL)
					ptrAntPedidos->sgte = ptrNuevoPedidos->sgte;
				else
				{
					ptrAntPedidos->sgte = NULL;
					listaPedidosSincroLast = ptrAntPedidos;
				}
			}
			else
				listaPedidosSincro = ptrNuevoPedidos->sgte;
			free(ptrNuevoPedidos->msg);
			free(ptrNuevoPedidos);
		}
	}
}

void eliminarPedidosDe( int32_t sockPD)
{
	tipoPedido* ptrNuevoPedidos;
	tipoPedido* ptrAntPedidos;
	ptrNuevoPedidos = listaPedidos;
	ptrAntPedidos = NULL;

	while ( ptrNuevoPedidos != NULL )
	{
		ptrAntPedidos = NULL;
		while( ptrNuevoPedidos != NULL && ptrNuevoPedidos->sock != sockPD )
		{
			ptrAntPedidos = ptrNuevoPedidos;
			ptrNuevoPedidos = ptrNuevoPedidos->sgte;
		}
		if( ptrNuevoPedidos != NULL )
		{
			if( ptrAntPedidos != NULL )
			{
				if(ptrNuevoPedidos->sgte != NULL)
					ptrAntPedidos->sgte = ptrNuevoPedidos->sgte;
				else
				{
					ptrAntPedidos->sgte = NULL;
					listaPedidosLast = ptrAntPedidos;
				}
			}
			else
				listaPedidos = ptrNuevoPedidos->sgte;
			free(ptrNuevoPedidos->msg);
			free(ptrNuevoPedidos);
		}
	}
}

void desincronizarDisco( int32_t sockPD )
{
	tipoDisco* ptrNuevoDiscos;

	ptrNuevoDiscos = listaDiscos;

	while ( ptrNuevoDiscos != NULL && ptrNuevoDiscos->sockDisco != sockPD)
		ptrNuevoDiscos = ptrNuevoDiscos->sgte;
	if (ptrNuevoDiscos != NULL)
		ptrNuevoDiscos->sinc = 0;
	return;
}

void* nuevoThreadDisco(void* paqueteThread)
{
	packThread* packTh = (packThread*) paqueteThread;
	Paquete* paquete = malloc(sizeof(Paquete));
	Paquete* unPaquete4free;

	int32_t sockPD = packTh->sock;
	int32_t sectores = packTh->cantSectores;
	int32_t i,rc,sockSincro;
	int32_t funciona = 1;
	int32_t vecSincro[sectores];
	int32_t sectoresSincro = 0;
	int32_t sendeados = 0;
	time_t comienzo, final;
	int cont;
	struct tm* fecha;
	paquete->Datos = malloc(512);

	char IDsincro[16];
	char* bufferEntrada = (char*) malloc ( sizeof(char)*BUFF_LIMIT);

	tipoPedido* ptrNuevoPedidos;
	tipoPedido* ptrAntPedidos;

	if( !estaSincronizado(sockPD) )
	{
		comienzo = time( NULL );
		fecha = localtime(&comienzo);
		printf("Inicio de sincronizacion de %s, %d:%d:%d\n",nombreDisco(sockPD),fecha->tm_hour,fecha->tm_min,fecha->tm_sec);
		RandomGG(IDsincro,16);
		pthread_mutex_lock( &mutexSincro );
		agregarSincro(IDsincro, sockPD);
		pthread_mutex_unlock ( &mutexSincro );
		for(i=0;i<sectores;i++)
			vecSincro[i] = 0;
		cont = 0;
	}
	while( !estaSincronizado(sockPD) && funciona && raidFuncionando )
	{
		rc = recv(sockPD,bufferEntrada,BUFF_LIMIT, MSG_PEEK | MSG_DONTWAIT );
		if(rc == 0)
		{
			// se callo el disco
			funciona = 0;
			break;
		}
		if ( sectoresSincro == sendeados )
		{
			sectoresSincro = sincronizarCon( sockPD, vecSincro, sectores, IDsincro, sectoresSincro );
			if( sectoresSincro == -1 )
				{
					funciona = 0;
				}
			if( verificarPedidosSincro(vecSincro,sectores) > 0 )
			{
				final = time( NULL );
				fecha = localtime(&final);
				discoSincronizadoOK(sockPD);
				printf("Fin de sincronizacion de %s, %d:%d:%d\n",nombreDisco(sockPD),fecha->tm_hour,fecha->tm_min,fecha->tm_sec);
				printf( "Tiempo que tardo la sincronizacion de %s: %d segundos\n",nombreDisco(sockPD),(int) difftime(final, comienzo) );
				eliminarSincro(IDsincro);
				do
				{
					paquete = revisarPUTwait(sockPD,vecSincro, paquete );
					if ( paquete->Tipo != 'X' )
					{
						pthread_mutex_lock( &mutexPedidos );
						nuevoPedido(sockPD,paquete);
						sem_post( &semPed );
						pthread_mutex_unlock ( &mutexPedidos );
					}
				}while ( paquete->Tipo != 'X' );
				break;
			}
		}
		if ( sem_trywait( &semPedSincro ) == 0 )
		{
			pthread_mutex_lock( &mutexPedidosSincro );
			ptrNuevoPedidos = listaPedidosSincro;
			while ( ptrNuevoPedidos != NULL )
			{
				ptrNuevoPedidos = listaPedidosSincro;
				ptrAntPedidos = NULL;
				while( ptrNuevoPedidos != NULL && ptrNuevoPedidos->sock != sockPD )
				{
					ptrAntPedidos = ptrNuevoPedidos;
					ptrNuevoPedidos = ptrNuevoPedidos->sgte;
				}
				if( ptrNuevoPedidos != NULL )
				{
					if( ptrAntPedidos != NULL )
					{
						if(ptrNuevoPedidos->sgte != NULL)
							ptrAntPedidos->sgte = ptrNuevoPedidos->sgte;
						else
							ptrAntPedidos->sgte = NULL;
					}
					else
						listaPedidosSincro = ptrNuevoPedidos->sgte;
					if( atenderPedidoSincro( ptrNuevoPedidos, sockPD, vecSincro ) < 0 )
					{
						//eliminarPedidos( sockPD ); hay q ver esto!
						pthread_mutex_unlock( &mutexPedidosSincro );
						break;
					}
					sendeados++;
					free(ptrNuevoPedidos->msg);
					free(ptrNuevoPedidos);
				}
			}
			pthread_mutex_unlock( &mutexPedidosSincro );
		}
	} /* TERMINO LA SINCRONIZACION WACHO */
	while( funciona && raidFuncionando )
	{
		// Atiende los pedidos
		if ( sem_trywait( &semPed) == 0 )
		{
			pthread_mutex_lock( &mutexPedidos );
			ptrNuevoPedidos = listaPedidos;
			if ( ptrNuevoPedidos != NULL )
			{
				ptrAntPedidos = NULL;
				while( ptrNuevoPedidos != NULL && ptrNuevoPedidos->sock != sockPD )
				{
					ptrAntPedidos = ptrNuevoPedidos;
					ptrNuevoPedidos = ptrNuevoPedidos->sgte;
				}
				if( ptrNuevoPedidos != NULL )
				{
					if( ptrAntPedidos != NULL )
					{
						if(ptrNuevoPedidos->sgte != NULL)
							ptrAntPedidos->sgte = ptrNuevoPedidos->sgte;
						else
							ptrAntPedidos->sgte = NULL;
					}
					else
						listaPedidos = ptrNuevoPedidos->sgte;
					if( atenderPedido( ptrNuevoPedidos, sockPD, vecSincro ) < 0 )
					{
						pthread_mutex_unlock( &mutexPedidos );
						break;
					}
					free(ptrNuevoPedidos->msg);
					free(ptrNuevoPedidos);
				}
				else /* si recorrio la lista al pedo */
					sem_post( &semPed );
			}
			pthread_mutex_unlock( &mutexPedidos );
		}
		rc = recv(sockPD,bufferEntrada,BUFF_LIMIT, MSG_PEEK | MSG_DONTWAIT );
		if( rc != 535 )
		{
			if(rc == 0)
			{
				// se callo el disco
				funciona = 0;
				break;
			}
		}
		else
		{
			rc = recv(sockPD,bufferEntrada,BUFF_LIMIT, MSG_DONTWAIT );
			if(rc == 0)
			{
				// se callo el disco
				funciona = 0;
				break;
			}
			unPaquete4free = DesSerializar(bufferEntrada);
			pthread_mutex_lock( &mutexSincro );
			sockSincro = esPedidoSincro(unPaquete4free->ID);
			pthread_mutex_unlock( &mutexSincro );
			if ( sockSincro > 0 )
			{
				unPaquete4free->Tipo = PUT_SECTOR_SINC;
				pthread_mutex_lock( &mutexAtendidos );
				eliminarAtendido(unPaquete4free->ID,unPaquete4free->Sector);
				pthread_mutex_unlock( &mutexAtendidos );
				pthread_mutex_lock( &mutexPedidosSincro );
				nuevoPedidoSincro(sockSincro,unPaquete4free);
				sem_post( &semPedSincro );
				pthread_mutex_unlock( &mutexPedidosSincro );
			}
			else
			{
				if( sockSincro != -1 )
				{
					if ( !sinFS )
					{
						pthread_mutex_lock(&mutexSockFS);
						rc = send(sockFS,bufferEntrada,535,0);
						if (rc < 0)
						{
							printf("Se desconecto el Proceso Filesystem\n");
							sinFS = 1;
							close(sockFS);
						}
						pthread_mutex_unlock( &mutexSockFS );
		//				printf("Enviando al FS sector: %d\n", unPaquete4free->Sector);
						pthread_mutex_lock( &mutexAtendidos );
						eliminarAtendido(unPaquete4free->ID,unPaquete4free->Sector);
						pthread_mutex_unlock( &mutexAtendidos );
					}
				}
			}
			free( unPaquete4free->Datos);
			free( unPaquete4free );
		} /* FIN ELSE RECV */
	} /* FIN WHILE */
	printf("%s Desconectado\n",nombreDisco(sockPD) );
	if( estaSincronizado(sockPD) )
	{
		pthread_mutex_lock( &mutexDiscos );
		desincronizarDisco( sockPD );
		pthread_mutex_unlock( &mutexDiscos );
		pthread_mutex_lock( &mutexAtendidos );
		actualizarPedidosDe(sockPD);
		pthread_mutex_unlock( &mutexAtendidos );
	}
	else
	{
		pthread_mutex_lock( &mutexPedidos );
		eliminarPedidosDe(sockPD);
		pthread_mutex_unlock( &mutexPedidos );
		pthread_mutex_lock( &mutexPedidosSincro );
		eliminarPedidosSincroDe(sockPD);
		pthread_mutex_unlock( &mutexPedidosSincro );
		pthread_mutex_lock( &mutexSincro );
		eliminarSincro(IDsincro);
		pthread_mutex_unlock( &mutexSincro );
	}
	char*  stringLog = (char*) malloc (sizeof(char)*128);
	strcpy( stringLog, "Se desconecto el disco: ");
	pthread_mutex_lock( &mutexDiscos );
	strcat( stringLog, (char*) nombreDisco( sockPD ) );
	escribir_logfile(NOMPS, (long int)syscall(224), INFO, stringLog );
	eliminarDisco( sockPD );
	close( sockPD );
	if( sinDiscosSinc() )
	{
		strcpy( stringLog, "PRAID DESTRUIDO" );
		escribir_logfile(NOMPS, (long int)syscall(224), INFO, stringLog );
		sinPD = 1;
//		raidFuncionando = 0;
	}
	pthread_mutex_unlock( &mutexDiscos);
	pthread_exit(NULL);
	return 0;
}
